'''

    Simple text editor Widget using SHIK input

'''

from PyQt4 import QtGui, QtCore, Qt

class _SHIKFilter(QtCore.QObject):
    def __init__( 
            self, text_edit,
            DL=QtCore.Qt.Key_A,
            DM=QtCore.Qt.Key_S,
            DR=QtCore.Qt.Key_D,
            UL=QtCore.Qt.Key_Q,
            UM=QtCore.Qt.Key_W,
            UR=QtCore.Qt.Key_E,
        ):
        QtCore.QObject.__init__( self, text_edit )
        self.text_edit = text_edit
        self.DL = DL
        self.DM = DM
        self.DR = DR
        self.UL = UL
        self.UM = UM
        self.UR = UR
        self.BADKEY = None # Used as an enum
        self.KEYS = (
            self.DL,
            self.DM,
            self.DR,
            self.UL,
            self.UM,
            self.UR,
        )
        self._keychain = []
        self._applied = False
        self._next_upper = False
        
        self._chainToText_base = {
        # No Mod
            (self.DL,):                 'a',
            (self.DM,):                 ' ',
            (self.DR,):                 'o',
            (self.UL,):                 'e',
            (self.UM,):                 't',
            (self.UR,):                 'i',
        # DL Mod
            (self.DL,self.DM,):         's',
            (self.DL,self.DR,):         'l',
            (self.DL,self.UL,):         'd',
            (self.DL,self.UM,):         'y',
            (self.DL,self.UR,):         'c',
        # DM Mod
            (self.DM,self.DR,):         'n',
            (self.DM,self.UL,):         'w',
            (self.DM,self.UM,):         'f',
            (self.DM,self.UR,):         'u',
        # DR Mod
            (self.DR,self.UL,):         'm',
            (self.DR,self.UM,):         'g',
            (self.DR,self.UR,):         QtCore.Qt.Key_Backspace,
        # UL Mod
            (self.UL,self.UM,):         'r',
            (self.UL,self.UR,):         'd',
        # UM Mod
            (self.UM,self.UR,):         'h',
        # DL+DM Mod
            (self.DL,self.DM,self.DR,): self._upper_one,
            (self.DL,self.DM,self.UR,): 'p',
        # DL+DR Mod
            (self.DL,self.DR,self.UM,): self._set_more_char,
        # DL+UM Mod
            (self.DL,self.UM,self.UR,): 'f',
        # DM+DR Mod
            (self.DM,self.DR,self.UL,): 'b',
        # DR+UL Mod
            (self.DR,self.UL,self.UM,): 'v',
        }
        
        self._chainToText_more_char = {
        # No Mod
            (self.DL,):  'z',
            (self.DM,):  'x',
            (self.DR,):  '\n',
            (self.UL,):  'q',
            (self.UM,):  'j',
            (self.UR,):  'k',
            (self.DL,self.UR,):         self._copy_text,
        }
        
        self._chainToText = self._chainToText_base

    def _key_name(self, key):
        if key == self.BADKEY:
            return 'BADKEY'
        return chr(key)
        
    def _keychain_str(self):
        return ', '.join([ self._key_name(k) for k in self._keychain ])

    def key_from_event(self, event):
        if event.key() not in self.KEYS:
            return self.BADKEY
        return event.key()

    def apply(self):
        '''
        Apply current key sequence and go in release mode.
        '''
        # Go to applied mode (do nothing until next press)
        self._applied = True
        if self.BADKEY in self._keychain:
            # Do nothing if we have pressed some bad key
            return None
        keychain = set(self._keychain)
        ret = None
        for k, v in self._chainToText.iteritems():
            if set(k) == keychain:
                ret = v
                break
        # Reset to default map:
        self._set_base()
        # Exec callback if given:
        if callable(ret):
            ret = ret()
        if ret is not None and self._next_upper:
            ret = ret.upper()
            self._next_upper = False
        return ret
        
    def eventFilter( self, obj, event ):
        if obj != self.text_edit:
            return False
        
        if event.type() == QtCore.QEvent.KeyPress:
            #print 'press', chr(event.key())
            self._applied = False
            k = self.key_from_event(event)
            if k not in self._keychain:
                self._keychain.append(k)
                #print '  >>', self._keychain_str()
        
        if event.type() == QtCore.QEvent.KeyRelease:
            #print 'release', chr(event.key())
            if not self._applied:
                text = self.apply()
                if isinstance(text,int):
                    obj.keyPressEvent(
                        QtGui.QKeyEvent(
                            QtCore.QEvent.KeyPress,
                            text,
                            QtCore.Qt.KeyboardModifiers()
                        )
                    )
                elif text is not None:
                    #print ">>>", repr(text)
                    self.text_edit.insertPlainText(text)
            k = self.key_from_event(event)
            if k in self._keychain:
                self._keychain.remove(k)
            #print '  >>', self._keychain_str()
        
        return True # eat event

    def _set_base(self):
        #print "-> base"
        self._chainToText = self._chainToText_base

    def _set_more_char(self):
        #print "-> more char"
        self._chainToText = self._chainToText_more_char

    def _upper_one(self):
        self._next_upper = True
        #print "NEXT UPPER!!!"
    
    def _copy_text(self):
        print "COPY!!!"
        
class _SHIKFilter_QWERTY(_SHIKFilter):
    pass

class _SHIKFilter_AZERTY(_SHIKFilter):
    def __init__(self, text_edit):
        _SHIKFilter.__init__(
            self, text_edit,
            DL=QtCore.Qt.Key_Q,
            DM=QtCore.Qt.Key_S,
            DR=QtCore.Qt.Key_D,
            UL=QtCore.Qt.Key_A,
            UM=QtCore.Qt.Key_Z,
            UR=QtCore.Qt.Key_E,
        )

class _SHIKFilter_HNUMPAD(_SHIKFilter):
    def __init__(self, text_edit):
        _SHIKFilter.__init__(
            self, text_edit,
            DL=QtCore.Qt.Key_3,
            DM=QtCore.Qt.Key_6,
            DR=QtCore.Qt.Key_9,
            UL=QtCore.Qt.Key_2,
            UM=QtCore.Qt.Key_5,
            UR=QtCore.Qt.Key_8,
        )    

class TextEdit( QtGui.QTextEdit ):
    def __init__( self, parent ):
        QtGui.QTextEdit.__init__( self, parent )
        self.installEventFilter( _SHIKFilter_QWERTY(self) )
